#pragma once

#include "imageclass_decl.h"
#include <string>
#include <iostream>
#include <cassert>

namespace xml { class stream; }

namespace img {

//R - bitmap, mono_byte_image, small_byte_image, byte_image

template <class R>
std::ostream & hex_encode(R const & r, std::ostream & s);
template <class R>
void hex_encode(R const & r, std::string & hexstring);

template <class R>
std::istream & hex_decode(R & r, std::istream & s);
template <class R>
void hex_decode(R & r, std::string const & hexstring);

template <class R>
xml::stream & operator >> (xml::stream & s, R & b);
template <class R>
xml::stream & operator << (xml::stream & s, R const & b);

template <class R>
xml::stream & serialize(xml::stream & s, R & b);

xml::stream & operator || (xml::stream & s, bitmap & b);
xml::stream & operator || (xml::stream & s, mono_byte_image & b);
xml::stream & operator || (xml::stream & s, small_byte_image & b);
xml::stream & operator || (xml::stream & s, byte_image & b);

// hex iterators

class ostream_hex_iterator : public std::iterator<std::output_iterator_tag, char>
{
	std::ostream & _ostream;
	char _buf;
public:
	ostream_hex_iterator(std::ostream & s) : _ostream(s) 
	{
		s.unsetf(std::ios::dec);
		s.setf(std::ios::hex);
		s.fill('0');
	}
	ostream_hex_iterator & operator ++ () {
		_ostream.width(2);
		_ostream << (int)(unsigned char)(_buf); 
		return * this;
	}
	char & operator * ()
		{ return _buf; }
};

class istream_hex_iterator : public std::iterator<std::input_iterator_tag, char>
{
	std::istream * _istream;
	char _buf;

public:	
	typedef char	value_type;
	typedef char* 	pointer;
	typedef char& 	reference; //???
	typedef ptrdiff_t	difference_type;
	typedef std::input_iterator_tag	iterator_category;

public:
	istream_hex_iterator() : _istream(0) {}
	istream_hex_iterator(std::istream & s) : _istream(&s)
	{
		s.unsetf(std::ios::dec);
		s.setf(std::ios::hex);
		operator ++();
	}
	istream_hex_iterator & operator ++ () {
		char c[3];
		c[2] = 0;
		*_istream >> c[0] >> c[1];
		if (_istream->eof())
			return * this;
		char * endptr;
		_buf = (char) strtol(c, &endptr, 16);
		assert(endptr == c+2);
		return * this;
	}
	const char & operator * () const
		{ return _buf; }
	friend bool operator == (const istream_hex_iterator & lhs, const istream_hex_iterator & rhs) {
		if (lhs._istream == 0) {
			if (rhs._istream == 0 || rhs._istream->eof())
				return true;
		}
		if (rhs._istream == 0 && lhs._istream->eof())
			return true;
		return false;
	}
	friend bool operator != (const istream_hex_iterator & lhs, const istream_hex_iterator & rhs) 
		{ return !(lhs == rhs); }
};

} //namespace img
